package com.gitee.wsl.compose.animation

import androidx.compose.animation.animateColor
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationVector
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.TargetBasedAnimation
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.TwoWayConverter
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateInt
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.animateIntOffsetAsState
import androidx.compose.animation.core.animateIntSizeAsState
import androidx.compose.animation.core.animateOffsetAsState
import androidx.compose.animation.core.animateRectAsState
import androidx.compose.animation.core.animateSizeAsState
import androidx.compose.animation.core.animateValue
import androidx.compose.animation.core.animateValueAsState
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.BiasAlignment
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.BaselineShift
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import com.gitee.wsl.compose.animation.spec.Spac

//无限重复动画
@Composable
fun A.infiniteTransition(label:String ="InfiniteTransition") = androidx.compose.animation.core.rememberInfiniteTransition(label)

//组合动画
@Composable
fun <T> A.transition(init:T,block: MutableTransitionState<T>.()->Unit={}) = remember { MutableTransitionState(init).apply(block) }

//组合动画
@Composable
fun A.transition(init:Boolean=false) = transition(init){targetState=!init}

//组合动画
@Composable
fun <T:Number> A.transition(start:T,end:T) = transition<T>(start){targetState=end}


//TargetBasedAnimation 可以控制动画的执行时间，还可以延迟一段时间再开启动画。
@Composable
fun <T, V : AnimationVector> A.targetBased(animationSpec: AnimationSpec<T>,
                                         typeConverter: TwoWayConverter<T, V>,
                                         initialValue: T,
                                         targetValue: T,
                                         initialVelocity: T)= remember {
    TargetBasedAnimation<T,V>(animationSpec, typeConverter, initialValue, targetValue, initialVelocity)
}

@Composable
fun A.color(
    targetValue: Color,
    animationSpec: AnimationSpec<Color> =  spring(),
    label: String = "ColorAnimation",
    finishedListener: ((Color) -> Unit)? = null
) = animateColorAsState(targetValue, animationSpec, label, finishedListener)

@Composable
fun A.float(targetValue: Float,
          animationSpec: AnimationSpec<Float> = A.Spac.defaultAnimation,
          visibilityThreshold: Float = 0.01f,
          label: String = "FloatAnimation",
          finishedListener: ((Float) -> Unit)? = null
) = animateFloatAsState(targetValue, animationSpec, visibilityThreshold, label, finishedListener)

@Composable
fun A.dp(
    targetValue: Dp,
    animationSpec: AnimationSpec<Dp> = A.Spac.dpDefaultSpring,
    label: String = "DpAnimation",
    finishedListener: ((Dp) -> Unit)? = null
) = animateDpAsState(targetValue, animationSpec, label, finishedListener)


@Composable
fun A.size(
    targetValue: Size,
    animationSpec: AnimationSpec<Size> = A.Spac.sizeDefaultSpring,
    label: String = "SizeAnimation",
    finishedListener: ((Size) -> Unit)? = null
) = animateSizeAsState(targetValue, animationSpec, label, finishedListener)

@Composable
fun A.offset(
    targetValue: Offset,
    animationSpec: AnimationSpec<Offset> = A.Spac.offsetDefaultSpring,
    label: String = "OffsetAnimation",
    finishedListener: ((Offset) -> Unit)? = null
) = animateOffsetAsState(targetValue, animationSpec, label, finishedListener)

@Composable
fun A.rect(
    targetValue: Rect,
    animationSpec: AnimationSpec<Rect> = A.Spac.rectDefaultSpring,
    label: String = "RectAnimation",
    finishedListener: ((Rect) -> Unit)? = null
) = animateRectAsState(targetValue, animationSpec, label, finishedListener)

@Composable
fun A.int(
    targetValue: Int,
    animationSpec: AnimationSpec<Int> = A.Spac.intDefaultSpring,
    label: String = "IntAnimation",
    finishedListener: ((Int) -> Unit)? = null
) = animateIntAsState(targetValue, animationSpec, label, finishedListener)

@Composable
fun A.intOffset(
    targetValue: IntOffset,
    animationSpec: AnimationSpec<IntOffset> = A.Spac.intOffsetDefaultSpring,
    label: String = "IntOffsetAnimation",
    finishedListener: ((IntOffset) -> Unit)? = null
) = animateIntOffsetAsState(targetValue, animationSpec, label, finishedListener)

@Composable
fun A.intSize(
    targetValue: IntSize,
    animationSpec: AnimationSpec<IntSize> = A.Spac.intSizeDefaultSpring,
    label: String = "IntSizeAnimation",
    finishedListener: ((IntSize) -> Unit)? = null
) = animateIntSizeAsState(targetValue, animationSpec, label, finishedListener)


/**
 * var state by remember {
 *         mutableStateOf(true)
 *     }
 *     val value by animateValueAsState(
 *         targetValue = if (state) AnimSize(0xffff5500, 100f) else AnimSize(0xff00ff00, 300f),
 *         typeConverter = TwoWayConverter(
 *             convertToVector = {
 *                 AnimationVector2D(it.color.toFloat(), it.size)
 *             },
 *             convertFromVector = {
 *                 AnimSize(it.v1.toLong(), it.v2)
 *             }
 *         )
 *     )
 */
//自定义类型 添加动画效果
@Composable
fun  <T, V : AnimationVector> A.valueOf(
    targetValue: T,
    typeConverter: TwoWayConverter<T, V>,
    animationSpec: AnimationSpec<T> = remember { spring() },
    visibilityThreshold: T? = null,
    label: String = "ValueAnimation",
    finishedListener: ((T) -> Unit)? = null
) = animateValueAsState(targetValue,typeConverter,animationSpec, visibilityThreshold, label, finishedListener)


@Composable
fun A.animatable(initialValue: Float,
               visibilityThreshold: Float = Spring.DefaultDisplacementThreshold
) = remember{ Animatable(initialValue, visibilityThreshold) }

@Composable
fun <T, V : AnimationVector> A.animatable(initialValue: T,
                                        typeConverter: TwoWayConverter<T, V>,
                                        visibilityThreshold: T? = null,
                                        label: String = "Animatable")
= remember { Animatable(initialValue,typeConverter,visibilityThreshold, label) }

@Composable
fun A.horizontalAlignment(
    targetAlignment: Alignment.Horizontal,
    animationSpec: AnimationSpec<Float> = tween()
): State<BiasAlignment.Horizontal> {
    val bias by animateFloatAsState(
        targetValue = when (targetAlignment) {
            Alignment.Start -> -1f
            Alignment.End -> 1f
            else -> 0f
        },
        animationSpec = animationSpec, label = ""
    )
    return remember { derivedStateOf { BiasAlignment.Horizontal(bias) } }
}

@Composable
fun A.textStyle(
    textStyle: TextStyle
): State<TextStyle> {
    val state = remember { mutableStateOf(textStyle) }

    val transition = updateTransition(textStyle, label = "animateTextStyleAsState")

    val color by transition.animateColor(label = "color") {
        it.color
    }
    val fontWeight by transition.animateInt(label = "fontWeight") {
        it.fontWeight?.weight ?: 400
    }
    val fontSize by transition.animateTextUnit {
        it.fontSize
    }
    val letterSpacing by transition.animateTextUnit {
        it.letterSpacing
    }
    val baselineShift by transition.animateFloat(label = "baselineShift") {
        it.baselineShift?.multiplier ?: 0f
    }
    val background by transition.animateColor(label = "background") {
        it.background
    }
    val lineHeight by transition.animateTextUnit {
        it.lineHeight
    }

    state.value = textStyle.copy(
        color = color,
        fontSize = fontSize,
        fontWeight = FontWeight(fontWeight),
        letterSpacing = letterSpacing,
        baselineShift = BaselineShift(baselineShift),
        background = background,
        lineHeight = lineHeight,
    )

    return state
}


@Composable
inline fun <S> Transition<S>.animateTextUnit(
    noinline transitionSpec:
    @Composable Transition.Segment<S>.() -> FiniteAnimationSpec<TextUnit> = { spring() },
    label: String = "ValueAnimation",
    targetValueByState: @Composable (state: S) -> TextUnit
): State<TextUnit> {
    return animateValue(
        typeConverter = TextUnitConverter,
        label = label,
        transitionSpec = transitionSpec,
        targetValueByState = targetValueByState
    )
}